/*
 *
 *  Copyright (C) 2012-2024
 *  All rights reserved, Designed By 杭州连线客信息技术有限公司
 *  注意：
 *  本软件为杭州连线客信息技术有限公司开发研制，未经购买不得使用
 *  购买后可获得全部源代码（禁止转卖、分享、上传到码云、github等开源平台）
 *  一经发现盗用、分享等行为，将追究法律责任，后果自负
 *
 */

package com.lxk.oms.flow.pay;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.lxk.event.helper.EventHelper;
import com.lxk.event.oms.OrderOptionLogEvent;
import com.lxk.event.oms.OrderPaySuccessEvent;
import com.lxk.event.oms.enums.OrderEnums;
import com.lxk.oms.order.domain.vo.OmsOrderVo;
import com.lxk.oms.order.service.IOmsOrderService;
import com.lxk.service.core.Result;
import com.lxk.service.finance.api.WalletServiceApi;
import com.lxk.service.finance.enums.AccountTypeEnum;
import com.lxk.service.finance.request.QueryAccountParam;
import com.lxk.service.finance.request.UpdateAccountParam;
import com.lxk.service.finance.response.UserAccountDto;
import com.lxk.service.ums.response.UmsUserDto;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.log.LFLog;
import com.yomahub.liteflow.log.LFLoggerManager;
import lombok.AllArgsConstructor;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.StreamUtils;

import java.math.BigDecimal;
import java.util.List;

/**
 * 余额支付节点-支持多订单同时支付
 *
 * @author heyi
 * 2024/8/22
 */
@LiteflowComponent(value = FlowPayOrderNodeConst.YU_PAY)
@AllArgsConstructor
public class YuPayNode extends NodeComponent {
    private final WalletServiceApi walletServiceApi;
    private final IOmsOrderService omsOrderService;
    private final LFLog log = LFLoggerManager.getLogger(FlowExecutor.class);

    @Override
    public void beforeProcess() {
        PayContext contextBean = getContextBean(PayContext.class);
        List<OmsOrderVo> omsOrderVoList = contextBean.getOmsOrder();
        String orderSnList = StreamUtils.join(omsOrderVoList, OmsOrderVo::getOrderNo);
        BigDecimal totalPayPrice = omsOrderVoList.stream().map(OmsOrderVo::getActPayPrice).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
        QueryAccountParam accountParam = new QueryAccountParam().setUserId(contextBean.getUserId()).setAccountType(AccountTypeEnum.MONEY.getCode());
        Result<UserAccountDto> result = walletServiceApi.queryByParam(accountParam);
        if (result.isFail()) {
            throw new ServiceException(result.getMsg());
        }
        UserAccountDto accountDto = result.getData();
        if (ObjectUtil.isNull(accountDto)) {
            log.error("账户异常,参数:{}", accountParam);
            throw new ServiceException("账户异常");
        }
        contextBean.setUserAccount(accountDto);
        BigDecimal amount = accountDto.getAmount();
        if (amount.compareTo(totalPayPrice) < 0) {
            log.error("您的余额不足,余额:{},订单支付金额:{},订单编号:{}", amount, totalPayPrice, orderSnList);
            if (CollUtil.size(omsOrderVoList) == 1) {
                sendYuNotEnoughEvent(contextBean, omsOrderVoList.get(0));
            }
            throw new ServiceException("您的余额不足,请充值");
        }

    }

    @Override
    public void process() throws Exception {
        PayContext contextBean = getContextBean(PayContext.class);
        UmsUserDto user = contextBean.getUser();
        List<OmsOrderVo> omsOrderVoList = contextBean.getOmsOrder();
        omsOrderVoList.forEach(omsOrder -> {
            UpdateAccountParam param = new UpdateAccountParam();
            param.setUserId(user.getUserId());
            param.setAccountType(contextBean.getUserAccount().getAccountType());
            param.setOrderSn(omsOrder.getOrderNo());
            param.setAmount(omsOrder.getActPayPrice());
            param.setExtraInfo(StrUtil.format("余额支付订单:{}", omsOrder.getOrderNo()));
            Result<Boolean> reduce = walletServiceApi.reduce(param);
            if (!(reduce.isSuccess() && reduce.getData())) {
                sendYuNotEnoughEvent(contextBean, omsOrder);
                throw new ServiceException("您的余额不足");
            }
            // 订单已支付
            contextBean.setPayStatus(true);
        });

    }

    @Override
    public void onSuccess() throws Exception {
        PayContext contextBean = getContextBean(PayContext.class);
        List<OmsOrderVo> omsOrderVoList = contextBean.getOmsOrder();
        omsOrderVoList.forEach(omsOrder -> {
            // 余额支付且支付成功了
            Boolean success = omsOrderService.paySuccess(omsOrder, null, OrderEnums.PayType.YU.getCode());
            if (!success) {
                throw new ServiceException("订单支付异常");
            }
            sendSuccessEvent(contextBean, omsOrder);
            OrderPaySuccessEvent successEvent = new OrderPaySuccessEvent();
            successEvent.setActPayPrice(omsOrder.getActPayPrice());
            UmsUserDto umsUserDto = contextBean.getUser();
            successEvent.setUserId(umsUserDto.getUserId());
            successEvent.setTenantId(contextBean.getTenantId());
            successEvent.setOrderType(omsOrder.getOrderType());
            successEvent.setOrderNo(omsOrder.getOrderNo());
            successEvent.setOrderId(omsOrder.getId());
            successEvent.setOrderName(omsOrder.getOrderName());
            EventHelper.publishEvent(successEvent);
        });

    }

    private void sendSuccessEvent(PayContext contextBean, OmsOrderVo omsOrder) {
        OrderOptionLogEvent createEvent = new OrderOptionLogEvent();
        UmsUserDto umsUserDto = contextBean.getUser();
        Long merId = omsOrder.getMerId();
        Long userId = umsUserDto.getUserId();
        String nickName = umsUserDto.getNickName();
        createEvent.setOrderSn(omsOrder.getOrderNo());
        createEvent.setUserId(userId);
        createEvent.setMerId(merId);
        createEvent.setTenantId(contextBean.getTenantId());
        createEvent.setOrderLogEnums(OrderOptionLogEvent.OrderLogEnums.ORDER);
        createEvent.setUserType(umsUserDto.getUserType());
        createEvent.setContent(
            OrderOptionLogEvent.OrderContentFormatEnums.PAY_SUCCESS_ORDER.formatContent(nickName,
                omsOrder.getOrderNo(),
                OrderEnums.PayType.getByCode(contextBean.getPayType()).getName())
        );
        EventHelper.publishEvent(createEvent);
    }


    private void sendYuNotEnoughEvent(PayContext contextBean, OmsOrderVo omsOrder) {
        UmsUserDto user = contextBean.getUser();
        UserAccountDto userAccount = contextBean.getUserAccount();
        OrderOptionLogEvent createEvent = new OrderOptionLogEvent();
        createEvent.setOrderSn(omsOrder.getOrderNo());
        createEvent.setUserId(user.getUserId());
        createEvent.setMerId(omsOrder.getMerId());
        createEvent.setTenantId(contextBean.getTenantId());
        createEvent.setOrderLogEnums(OrderOptionLogEvent.OrderLogEnums.ORDER);
        createEvent.setUserType(user.getUserType());
        createEvent.setContent(
            OrderOptionLogEvent.OrderContentFormatEnums.YU_NOT_ENOUGH.formatContent(user.getNickName(),
                userAccount.getAmount().toString(),
                omsOrder.getActPayPrice().toString()
            )
        );
        EventHelper.publishEvent(createEvent);
    }

}
